#!/usr/bin/env python
# encoding: utf-8
"""
vmfilelistener.py

Created by Clifford Meece on 2008-04-26.
Copyright (c) 2008 abeedoo.com. All rights reserved.
"""

import SocketServer
import socket
import os
import sys
import logging
import threading
import wx
import hmac
import hashlib
import string, random


port = 5706

logging.basicConfig(level=logging.DEBUG,
                    format='%(name)s: %(message)s',
                    )



class MyTaskBarIcon(wx.TaskBarIcon):
    def __init__(self, frame):
        wx.TaskBarIcon.__init__(self)

        self.frame = frame
        self.SetIcon(wx.Icon('vmfileproxy.png', wx.BITMAP_TYPE_PNG), 'vmfilelistener.py')
        self.Bind(wx.EVT_MENU, self.OnTaskBarActivate, id=1)
        self.Bind(wx.EVT_MENU, self.OnTaskBarDeactivate, id=2)
        self.Bind(wx.EVT_MENU, self.OnTaskBarClose, id=3)

    def CreatePopupMenu(self):
        menu = wx.Menu()
        menu.Append(1, 'Settings')
        menu.Append(2, 'Hide')
        menu.Append(3, 'Close')
        return menu

    def OnTaskBarClose(self, event):
        self.frame.Close()

    def OnTaskBarActivate(self, event):
        if not self.frame.IsShown():
            self.frame.Show()

    def OnTaskBarDeactivate(self, event):
        if self.frame.IsShown():
            self.frame.Hide()

        
        
class PrefDialog(wx.Dialog):
    def __init__(self, parent, id, title):
        wx.Dialog.__init__(self, parent, id, title)
        self.tskic = MyTaskBarIcon(self)
        # port
        self.lblPort = wx.StaticText(self, -1, "Port :")
        self.txtPort = wx.TextCtrl(self, -1)
        #self.txtPort.SetValue(readDefaults("com.abeedoo.vmfileproxy","port"))
        # use static IP?
        self.chkStaticIP = wx.CheckBox(self, -1,'Use static IP?')
        self.chkStaticIP.Bind(wx.EVT_CHECKBOX, self.OnCheckStatic)
        #blnStaticIP = parseBoolString(readDefaults("com.abeedoo.vmfileproxy","useStaticIP"))
        #self.chkStaticIP.SetValue(blnStaticIP)
        self.lblIP = wx.StaticText(self, -1, "IP address or hostname :")
        self.txtIP = wx.TextCtrl(self, -1, name = "IP")
        #if blnStaticIP:
        #    self.txtIP.Enable()
        #    self.lblIP.Enable()
        #else:
        #    self.txtIP.Enable(False)
        #    self.lblIP.Enable(False)
        # use password?
        self.chkPassword = wx.CheckBox(self, -1,'Use password')
        self.chkPassword.Bind(wx.EVT_CHECKBOX, self.OnCheckPassword)
        #blnUsePassword = parseBoolString(readDefaults("com.abeedoo.vmfileproxy","usePassword"))
        #self.chkPassword.SetValue(blnUsePassword)
        self.lblPassword = wx.StaticText(self, -1, "Password :")
        self.txtPassword = wx.TextCtrl(self, -1, name = "password",style=wx.TE_PASSWORD)
        # password confirmation
        self.lblPasswordConfirm = wx.StaticText(self, -1, "Password Confirm:")
        self.txtPasswordConfirm = wx.TextCtrl(self, -1, name = "confirm",style=wx.TE_PASSWORD)
        #if blnUsePassword:
        #    self.txtPassword.Enable()
        #    self.lblPassword.Enable()
        #    self.txtPasswordConfirm.Enable()
        #    self.lblPasswordConfirm.Enable()
        #else:
        #    self.txtPassword.Enable(False)
        #    self.lblPassword.Enable(False)
        #    self.txtPasswordConfirm.Enable(False)
        #    self.lblPasswordConfirm.Enable(False)
        # Save password
        sizer = wx.FlexGridSizer(7,2)
        sizer.Add(self.lblPort,0,wx.ALL,10)
        sizer.Add(self.txtPort,0,wx.ALL,10)
        sizer.Add(self.chkStaticIP,0,wx.ALL,10)
        sizer.Add(wx.StaticText(self, -1, ''), 0, wx.EXPAND|wx.ALL,10)
        sizer.Add(self.lblIP,0,wx.LEFT,30)
        sizer.Add(self.txtIP,0,wx.LEFT,10)
        sizer.Add(self.chkPassword,0,wx.ALL,10)
        sizer.Add(wx.StaticText(self, -1, ''), 0, wx.EXPAND|wx.ALL,10)
        sizer.Add(self.lblPassword,0,wx.LEFT,30)
        sizer.Add(self.txtPassword,0,wx.LEFT,10)
        sizer.Add(self.lblPasswordConfirm,0,wx.LEFT,30)
        sizer.Add(self.txtPasswordConfirm,0,wx.LEFT,10)
        sizer.Add(wx.StaticText(self, -1, ''), 0, wx.EXPAND|wx.ALL,10)
        sizer.Add(wx.StaticText(self, -1, ''), 0, wx.EXPAND|wx.ALL,10)
        self.SetAutoLayout(1)
        self.SetSizer(sizer)
        self.Layout()
    def OnCheckStatic(self, event):
        logger.debug("StaticIP checkbox clicked")
        logger.debug("StaticIP checkbox status: %s", str(self.chkStaticIP.GetValue()))
        bln = self.chkStaticIP.GetValue()
        #writeDefaults("com.abeedoo.vmfileproxy","useStaticIP",str(bln))
        if not bln:
            self.lblIP.Enable(False)
            self.txtIP.Enable(False)
        else:
            self.lblIP.Enable()
            self.txtIP.Enable()
    def OnCheckPassword(self, event):
        logger.debug("Use Password checkbox clicked")
        logger.debug("Use Password checkbox status: %s", str(self.chkPassword.GetValue()))
        bln = self.chkPassword.GetValue()
        #writeDefaults("com.abeedoo.vmfileproxy","usePassword",str(bln))
        if not bln:
            self.txtPassword.Enable(False)
            self.lblPassword.Enable(False)
            self.txtPasswordConfirm.Enable(False)
            self.lblPasswordConfirm.Enable(False)
        else:
            self.txtPassword.Enable()
            self.lblPassword.Enable()
            self.txtPasswordConfirm.Enable()
            self.lblPasswordConfirm.Enable()
        frameSizer= wx.BoxSizer(wx.VERTICAL)
        self.panel = ConnectionPage(self, -1)
        frameSizer.Add(self.panel,1,wx.EXPAND|wx.TOP|wx.BOTTOM|wx.LEFT|wx.RIGHT,10)
        self.SetAutoLayout(1)
        self.SetSizerAndFit(frameSizer)
        self.tskic = MyTaskBarIcon(self)
        self.Centre()
        self.Bind(wx.EVT_CLOSE, self.OnClose)

    def OnClose(self,e):
        logger.debug('pref close')
        logger.debug("port is %s",self.txtPort.GetValue())
        self.tskic.Destroy()
        self.Destroy()

class MyApp(wx.App):
    def OnInit(self):
        pref = PrefDialog(None, -1, 'Preferences')
        pref.Centre(wx.BOTH)
        #pref.ShowModal()
        #frame.Show(True)
        self.SetTopWindow(pref)
        logger = logging.getLogger('vmfilelistener')
        logger.info('Server on port:%s', port)
        vmfilelistenerServer = SocketServer.TCPServer((socket.gethostname(), port),FileRequestHandler)
        t = threading.Thread(target=vmfilelistenerServer.serve_forever)
        # todo put threading stuff back in?
        #vmfilelistenerServer.serve_forever()
        t.setDaemon(True)
        t.start()
        return True

class FileRequestHandler(SocketServer.StreamRequestHandler):
    def handle(self):
        challenge = getchallenge()
        logger.debug("Issued challenge: %s", repr(challenge))
        self.wfile.write(challenge)
        self.wfile.flush()
        # client got challenge, now read auth attempt
        response = self.rfile.readline()
        response = response.rstrip("\n")
        logger.debug("Client responds with: %s", response)
        myhmac = hmac.new('password',challenge,hashlib.sha1)
        mycalc = myhmac.hexdigest()
        logger.debug("I calculate response should be: %s", mycalc)
        if mycalc == response:
            logger.debug('Authentication successful')
            self.wfile.write('SUCCESS')
            self.wfile.flush()
            path = self.rfile.readline().rstrip()
            logger.debug("Client sends path: %s", path)
            try:
                os.startfile(path)
            except WindowsError, e:
                logger.debug("Error opening file:%s",  e.strerror)
                self.wfile.write(e.strerror)
                return
            self.wfile.write('SUCCESS')
            self.wfile.flush()
        else:
            logger.debug('Client Auth failed')
            self.wfile.write('FAILURE')
            self.wfile.flush()
            
def getchallenge():
    # generate a 16-byte long random string.  (note that the built-
    # in pseudo-random generator uses a 24-bit seed, so this is not
    # as good as it may seem...)
    challenge = map(lambda i: chr(random.randint(0, 255)), range(16))
    return string.join(challenge, "")


logger = logging.getLogger('vmfilelistener')
logger.debug('Starting')
app = MyApp(0)
app.MainLoop()
logger.debug('Stopping')


